package com.baitiaojun.user.service.impl;


import com.baitiaojun.api.domain.user.FollowingGroup;
import com.baitiaojun.api.domain.user.UserFollowing;
import com.baitiaojun.api.domain.user.UserInfo;
import com.baitiaojun.api.exception.ConditionException;
import com.baitiaojun.api.util.AESUtil;
import com.baitiaojun.api.util.ConstantUtil;
import com.baitiaojun.api.util.SnowFlakeUtil;
import com.baitiaojun.user.config.properties.FollowingGroupProperties;
import com.baitiaojun.user.mapper.UserFollowingMapper;
import com.baitiaojun.user.service.FollowingGroupService;
import com.baitiaojun.user.service.UserFollowingService;
import com.baitiaojun.user.service.UserInfoService;
import com.baitiaojun.user.support.RedisSupport;
import com.baitiaojun.user.support.UserSupport;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @类名 UserFollowingServiceImpl
 * @作者 白条君
 * @创建日期 2022/10/29 19:35
 * @版本 1.0
 */
@Slf4j
@Service
public class UserFollowingServiceImpl implements UserFollowingService {

    @Resource
    private FollowingGroupService followingGroupService;

    @Resource
    private UserInfoService userInfoService;

    @Resource
    private UserFollowingMapper userFollowingMapper;

    @Resource
    private RedisSupport redisSupport;

    @Autowired
    private FollowingGroupProperties followingGroupProp;

    @Override
    @Transactional
    public void addAndUpdateUserFollowing(UserFollowing userFollowing, String token) throws Exception {
        Long userid = userFollowing.getUserid();
        Long followingid = userFollowing.getFollowingid();
        //不能对自己进行关注
        if(userid.equals(followingid)) {
            throw new ConditionException("用户不能对自己进行关注");
        }
        Long userId = userInfoService.getOtherUserId(userFollowing.getFollowingid());
        Integer user = userInfoService.getIsExistsUserById(userId);
        //查询要关注的用户是否存在
        if (ObjectUtils.isEmpty(user)) {
            throw new ConditionException("关注的用户不存在");
        }
        Long groupId = userFollowing.getGroupid();
        if (ObjectUtils.isEmpty(groupId)) {
            userFollowing.setGroupid(followingGroupProp.getId()[0]);
        } else if (groupId != followingGroupProp.getId()[0] && groupId != followingGroupProp.getId()[1]){
            //当groupId != 0 && groupId != 1就查看该数据库的记录是否存在
            Integer followingGroup = followingGroupService.getFollowingGroupIsExistsById(userFollowing.getGroupid());
            if (ObjectUtils.isEmpty(followingGroup)) {
                throw new ConditionException("用户分组不存在");
            }
        }
        //先删除当前用户和关注用户的关联信息，因为如果当一个所关注用户的group发生了更改，需要先删除原先建立的关联，重新给这个关注用户生成一个关联关系，也就是对所关注的用户进行更新
        if (!ObjectUtils.isEmpty(userFollowingMapper.selectIsExistsUserFollowingByFollowingId(userid, followingid))) {
            int res = userFollowingMapper.deleteByUseridAndFollowingid(userid, followingid);
            if (res == 0) {
                throw new ConditionException("关注用户删除失败");
            }
        }
        //建立用户和所要关注up主的关联关系
        userFollowing.setCreatetime(new Date());
        userFollowing.setId(SnowFlakeUtil.getNextId());
        int res = userFollowingMapper.insertSelective(userFollowing);
        if (res == 0) {
            throw new ConditionException("关注up主失败");
        }
        //当前用户新增关注用户或者更新关注用户，都要重新更新到redis缓存
        redisSupport.setHash(token, ConstantUtil.Field.USER_FOLLOWING.getKey(), getUserFollowings(userFollowing));
    }

    @Override
    public Object getUserFollowings(String token, UserFollowing userFollowing) throws Exception {
        //当前用户的关注用户先从redis缓存获取
        Object categoryGroupFromRedis = redisSupport.getHash(token, ConstantUtil.Field.USER_FOLLOWING.getKey());
        //如果缓存中无法获取数据，就先从持久层数据库获取再存到redis缓存,不存在共享key，所以不用解决缓存击穿问题等问题
        if (ObjectUtils.isEmpty(categoryGroupFromRedis)) {
            List<FollowingGroup> followingGroup = getUserFollowings(userFollowing);
            //将数据库数据添加到缓存，下次当前用户访问直接从缓存获取
            redisSupport.setHash(token, ConstantUtil.Field.USER_FOLLOWING.getKey(), followingGroup);
            return followingGroup;
        } else {
            return categoryGroupFromRedis;
        }
    }

    @Override
    public List<FollowingGroup> getUserFollowings(UserFollowing userFollowing) throws Exception {
        Long userid = userFollowing.getUserid();
        //从following-group.properties中获取默认分组和特别分组
        FollowingGroup followingGroup_default = FollowingGroup.builder().id(followingGroupProp.getId()[0])
                .name(followingGroupProp.getName()[0])
                .type(followingGroupProp.getType()[0]).build();
        FollowingGroup followingGroup_special = FollowingGroup.builder().id(followingGroupProp.getId()[1])
                .name(followingGroupProp.getName()[1])
                .type(followingGroupProp.getType()[1]).build();
        //获取所有关注用户的关联信息：关注用户的id、所在分组
        List<UserFollowing> userFollowingList = userFollowingMapper.selectUserFollowingListByUserId(userid);
        Set<Long> followingIds = collectUserFollowing((e) -> e.getFollowingid(), userFollowingList);
        //categoryGroup：返回前端的分组数据集合，主要是读操作这里使用ArrayList
        List<FollowingGroup> categoryGroup = new ArrayList<>();
        //默认填充DEFAULT和SPECIAL分组
        categoryGroup.add(followingGroup_special);
        categoryGroup.add(followingGroup_default);
        //查看当前用户是否有自定义分组，如果存在自定义分组就添加到categoryGroup
        List<FollowingGroup> followingGroups = followingGroupService.getFollowingGroupByUserId(userid);
        if (followingGroups.size() > 0) {
            followingGroups.forEach(followingGroup -> categoryGroup.add(followingGroup));
        }
        //如果没有关注的用户，就返回空的categoryGroup分组集合
        if (followingIds.size() == 0) {
            return categoryGroup;
        }
        //如果当前用户有关注的用户，就获取当前用户所关注的所有用户基本信息
        Set<Long> userIds = userInfoService.batchGetUserIdsFollowingIds(followingIds);
        List<UserInfo> userInfoList = userInfoService.getUserInfoListByUserId(userIds, userid);
        //将当前用户所有关注用户的每个userinfo数据一对一关联到相应的每个userfollowing对象中，方便后续操作
        AESUtil aesUtil = AESUtil.lazyGetAesUtil();
        for (UserFollowing following : userFollowingList) {
            for (UserInfo userInfo : userInfoList) {
                if (userInfo.getId().equals(following.getFollowingid())) {
                    following.setUserInfo(userInfo);
                    userInfo.setFollowing(true);
                }
                userInfo.setAvatar(aesUtil.encrypt(userInfo.getAvatar()));
                userInfo.setUserid(null);
                userInfo.setFollowed(null);
            }
        };
        //获取当前用户在关联信息(userFollowing)中所有关注用户的groupid
        Set<Long> followingGroupIds = collectUserFollowing((e) -> e.getGroupid(), userFollowingList);
        //根据当前用户所有关注用户的分组id，也就是groupid，从数据库获取所有关注用户的分组（这里的分组是用户自定义的分组）
        List<FollowingGroup> followingGroupList = followingGroupService.getFollowingGroupListByGroupIds(followingGroupIds);
        //如果size是0说明关注用户的组是属于默认或者特别分组，根据followingGroupIds进行匹配，获取关注用户属于默认分组还是特别关注分组
        followingGroupIds.forEach(followingGroupId -> {
            if (followingGroupId.equals(followingGroupProp.getId()[0])) {
                followingGroupList.add(followingGroup_default);
            } else if (followingGroupId.equals(followingGroupProp.getId()[1])) {
                followingGroupList.add(followingGroup_special);
            }
        });
        //将每一个分组和每一个关注用户的关联信息进行匹配，如果当前followingGroup分组的id和关联信息中的用户的分组id一样，就把这个关联信息中的userinfo归纳到sameCategoryUserInfoList，形成同组数据集合
        followingGroupList.forEach(followingGroup -> {
            List<UserInfo> sameCategoryUserInfoList = new ArrayList<>();
            userFollowingList.forEach(following -> {
                if (followingGroup.getId().equals(following.getGroupid())) {
                    sameCategoryUserInfoList.add(following.getUserInfo());
                }
            });
            //分组集合categoryGroup中找到与当前分组followingGroup匹配的分组group，然后把当前分组的所有UserInfo数据放进这个分组中，并统计分组的数据个数
            categoryGroup.forEach(group -> {
                if (followingGroup.getId().equals(group.getId())) {
                    group.setSameCategoryUserInfoList(sameCategoryUserInfoList);
                    group.setCount(sameCategoryUserInfoList.size());
                }
            });
        });
        //分组按照id序号排序，从小到大
        categoryGroup.sort((o1, o2) -> {
            Long id1 = o1.getId();
            if (ObjectUtils.isNotEmpty(id1)) {
                return id1.compareTo(o2.getId());
            }
            return 0;
        });
        //返回这个分组数据集合
        return categoryGroup;
    }

    public <T> Set<Long> collectUserFollowing(Function<? super T, ? extends Long> mapper, List<T> list) {
        Stream<T> stream = list.stream();
        return stream.map(mapper).collect(Collectors.toSet());
    }

    @Override
    public void cancelUserFollowing(Long currentUserId, UserFollowing userFollowing, String token) throws Exception {
        Long followingid = userFollowing.getFollowingid();
        if (ObjectUtils.isEmpty(followingid)) {
            throw new ConditionException("要取消所关注用户的userinfoId不能为空");
        }
        int res = userFollowingMapper.deleteByUseridAndFollowingid(currentUserId, followingid);
        if (res == 0) {
            throw new ConditionException("取消关注用户失败");
        }
        userFollowing.setUserid(currentUserId);
        redisSupport.setHash(token, ConstantUtil.Field.USER_FOLLOWING.getKey(), getUserFollowings(userFollowing));
        redisSupport.delete("subscribed" + currentUserId);
    }

    @Override
    public List<UserFollowing> getUserFollowingsInThisGroup(Long groupId) {
        return userFollowingMapper.selectByGroupId(groupId);
    }

    @Override
    public void batchMoveUserFollowingGroup(List<Long> ids, Long groupId) throws ConditionException {
        int res = userFollowingMapper.batchMoveUserFollowingGroup(ids, groupId);
        if (res == 0) {
            throw new ConditionException("批量更新关注用户的分组失败");
        }
    }

    public Integer getFollowingCount(Long userId) {
        return userFollowingMapper.followingCountByUserId(userId);
    }
    
    @Override
    public Set<Long> getUserFollowingIdsByUserId(Long userId) {
        List<UserFollowing> userFollowings = userFollowingMapper.selectUserFollowingListByUserId(userId);
        return userFollowings.stream().map(UserFollowing::getFollowingid).collect(Collectors.toSet());
    }

    @Override
    public Set<Long> getFollowingUserIdsByUserId(Long userId) throws ConditionException {
        if (ObjectUtils.isEmpty(userId)) {
            throw new ConditionException("参数异常");
        }
        return userFollowingMapper.selectFollowingUserIdsByUserId(userId);
    }
}